// This is the main project file for VC++ application project 
// generated using an Application Wizard.

#include "stdafx.h"

#using <mscorlib.dll>
#include <vcclr.h>

using namespace System;
#define LOGFILE "log.txt"

int _CommentCount;
int _TreeFlag=0;

__gc class BinaryTreeNode 
{
	public:
	System::String* tokenName;
	System::Collections::ArrayList* lineNumberList;
	int freq;
	BinaryTreeNode* leftChild;
	BinaryTreeNode* rightChild; 
	BinaryTreeNode::BinaryTreeNode()
	{
		freq=0;
		lineNumberList=new System::Collections::ArrayList();
	}
};
__gc class Tokens
{
	public: 
		System::String* tokenName;
		int lineNumber;
};

System::Collections::ArrayList* getTokensBySpace(System::String* str)
{
	String* delimStr = S" (){}[]|&!=<>?:;\t";
	Char delimiter[] = delimStr->ToCharArray();
	String* split[] = 0;
	System::Collections::ArrayList* arrResult=new System::Collections::ArrayList();
	split = str->Split(delimiter);
	System::Collections::IEnumerator* myEnum = split->GetEnumerator();
    while (myEnum->MoveNext()) {
       String* s = __try_cast<String*>(myEnum->Current);
	   if(s->StartsWith("//")) break;
	   if((s->Trim())->Equals("")) continue; 
	   arrResult->Add(s);
     }
	return arrResult;
}

int log(System::IO::StreamWriter* logger, System::Object* obj)
{
	logger->WriteLine(obj->ToString());
	logger->Flush();
	return 0;
}

int searchNodeBinaryTree(BinaryTreeNode* rootNd, Tokens* token)
{
	if(rootNd!=NULL)
	{
		if(rootNd->tokenName->Equals(token->tokenName))
		{
			rootNd->lineNumberList->Add(System::Convert::ToString(token->lineNumber));
			rootNd->freq++;
			return 0;
		}
		else
		{
			if(::searchNodeBinaryTree(rootNd->leftChild,token) && ::searchNodeBinaryTree(rootNd->rightChild,token))
				return 1;
			else
				return 0; 
		}
	}
	else
	{
		return 1; 
	}
}

int insertNodeBinaryTree(BinaryTreeNode* rootNd, Tokens* token)
{
	if(rootNd!=NULL)
	{
		BinaryTreeNode* newNode=new BinaryTreeNode();
		newNode->freq=1;
		newNode->tokenName=token->tokenName;
		newNode->lineNumberList->Add(System::Convert::ToString(token->lineNumber));
		newNode->leftChild=NULL;
		newNode->rightChild=NULL;
		if(rootNd->leftChild==NULL)
		{
			rootNd->leftChild=newNode;
			return 0;
		}
		if(rootNd->rightChild==NULL)
		{
			rootNd->rightChild=newNode;
			return 0;
		}
		if(!_TreeFlag)
		{
			::insertNodeBinaryTree(rootNd->leftChild,token);
		}
		else
		{
			::insertNodeBinaryTree(rootNd->rightChild,token);
		}
		_TreeFlag=!_TreeFlag;
		return 0;
	}
	else
	{
		return 1; 
	}
}

BinaryTreeNode* populateBinaryTree(System::Collections::ArrayList* tokenArray)
{
	int i;
	if(tokenArray!=NULL && tokenArray->Count>0)
	{
		Tokens* tokenObj=__try_cast<Tokens*>(tokenArray->Item[0]);

		BinaryTreeNode *root=new BinaryTreeNode();
		root->leftChild=NULL;
		root->rightChild=NULL;
		root->tokenName=tokenObj->tokenName;
		root->freq=1; 
		root->lineNumberList->Add(System::Convert::ToString(tokenObj->lineNumber));
		for(i=1;i<tokenArray->Count;i++)
		{
			Tokens* tokenObj=__try_cast<Tokens*>(tokenArray->Item[i]);
			int searchResult=::searchNodeBinaryTree(root,tokenObj);
			if(searchResult)
			{
				::insertNodeBinaryTree(root,tokenObj);
			}
		}
		return root;
	}
	else
	{
		return NULL;
	}
}

int printBinaryTree(BinaryTreeNode* root, int level)
{
	if(root!=NULL)
	{
		System::String* str="";
		for(int i=0;i<root->lineNumberList->Count;i++)
		{
			System::String* ii=__try_cast<System::String*>(root->lineNumberList->Item[i]);
			str=System::String::Concat(str,ii,new System::String(","));
		}
		for(int j=0;j<level;j++)
			Console::Write(" ");
		Console::WriteLine(System::String::Concat(new System::String("Name : "),root->tokenName,new System::String(" Freq : "),System::Convert::ToString(root->freq),new System::String(" Line number list : "),str));
		level++;
		::printBinaryTree(root->leftChild,level);
		::printBinaryTree(root->rightChild,level);
	}
	return 0;
}

int createBinaryTree(System::IO::StreamWriter* logger, System::IO::StreamReader* sr)
{
	int i=0;
	int _lineCt=0;
	char c[1];
	c[0]=',';
	System::String* contents="";
	System::String* line;
	System::Collections::ArrayList* finalTokenList=new System::Collections::ArrayList();
	while((line=sr->ReadLine())!=NULL)
	{
		_lineCt++;
		if(line->StartsWith("//"))
		{_CommentCount++;continue;}
		if(line->StartsWith("#"))
			continue;

		System::Collections::ArrayList* arr=::getTokensBySpace(line);
		System::Collections::ArrayList* tokenArr=new System::Collections::ArrayList();
		for(i=0;i<arr->Count;i++)
		{
			Console::WriteLine(__try_cast<String*>(arr->Item[i]));
			::log(logger,__try_cast<String*>(arr->Item[i]));
			
			Tokens* token=new Tokens();
			token->tokenName=__try_cast<String*>(arr->Item[i]);
			token->lineNumber=_lineCt;
			tokenArr->Add(token);
		}
		finalTokenList->AddRange(tokenArr);
	}
	BinaryTreeNode* rootNd=populateBinaryTree(finalTokenList);
	::printBinaryTree(rootNd,0);
	return 0;
}

int loadKeywordFile()
{
	System::Collections::ArrayList* keywordList;
	System::IO::StreamReader* sr=new System::IO::StreamReader("keywords.dat");
	System::String* line;
	keywordList=new System::Collections::ArrayList();
	while((line=sr->ReadLine())!=NULL)
	{
		keywordList->AddRange(::getTokensBySpace(line));
	}
	return 0;
}

int _tmain()
{
	System::IO::StreamWriter* logger=new System::IO::StreamWriter(LOGFILE);
	_CommentCount=-1; 
	Console::WriteLine("Enter file name :");
	System::String* filename=Console::ReadLine();
	System::IO::StreamReader* sr=new System::IO::StreamReader(filename);
	createBinaryTree(logger,sr);
	getchar();
	logger->Close();
	return 0;
}